/*
#include <vector>
#include <stdio.h>
#include <conio.h>
#include <string.h>
*/
#ifndef _NETWORK_SYSTEM_H
#define _NETWORK_SYSTEM_H

static const int DEFAULT_PLAYER_DELAY=50;

#include "Ape/TestObjects.h"
#include "Ape/myPhysics.h"

//My screen text output class
//#include "TextOutput.h"

#include "StringTable.h"
#include "RakPeerInterface.h"
#include "RakNetworkFactory.h"
#include "BitStream.h"
#include "MessageIdentifiers.h"
#include "ReplicaManager2.h"
#include "NetworkIDManager.h"
#include "RakSleep.h"
#include "FormatString.h"
#include "StringCompressor.h"

#include "NetworkIDManager.h"
#include "RakAssert.h"

extern SceneManager *sceneManager;
extern RakPeerInterface *rakPeer;
NetworkIDManager networkIdManager;
ReplicaManager2 replicaManager;
ReplicaManager2DemoConnectionFactory connectionFactory;
extern Packet *packet;
const char *UserName;
//char UserName[128];
String UserPass;
extern Entity *ent;
//AnimationState *mAnimationState; // The current animation state of the object

static int MAX_PLAYERS = 1;
//static const int DEFAULT_PLAYER_DELAY=1000;

//bool isServer;

class User;

using namespace Ogre;
using namespace RakNet;

class RakNetClient
{
public: 

		//debugin'
	//OgreText *debug1;
	//OgreText *debug2;
	//OgreText *debug3;
	//OgreText *debug4;

	Vector3 OldPos;
	//OgreQueueText *textQueueList;

	ProjectileManager *pm;

	RakNetClient(SceneManager *sMgr) { //ProjectileManager *projman OgreQueueText *txtQ
		char ch;
		char ip[128];
		static const int SERVER_PORT=60000;

		Soldier::mySoldier=0;
		User::myUser=0;		
		rakPeer = RakNetworkFactory::GetRakPeerInterface();
	
		//debug1 = new OgreText("debug1");
		//debug2 = new OgreText("debug2");
		//debug3 = new OgreText("debug3");
		//debug4 = new OgreText("debug4");

		sceneManager = sMgr;
		
		createCharacterEntity();

		OldPos = Vector3(0,0,0);
		//UserName = NULL;
		//UserPass = NULL;

		//pm = projman;
	}

	~RakNetClient() {
		//delete debug1;
		//delete debug2;
		//delete debug3;
		//delete debug4;

		Disconnect();
	}

	void createCharacterEntity()
	{
		ent = sceneManager->createEntity("Character", "ninja.mesh");
	}

	void Disconnect()
	{
		rakPeer->Shutdown(100,0);
		RakNetworkFactory::DestroyRakPeerInterface(rakPeer);
		return;
	}

	bool Connect(const char *ClientPort, const char *IP, const char *ServerPort, const char *User,const char *Pass)
	{

		UserName = User;
		UserPass = Pass;

		//rakPeer->InitializeSecurity(0,0,0,0);
		//rakPeer->AllowConnectionResponseIPMigration(false);
		RakNet::StringTable::Instance()->AddString("Soldier", false);
		RakNet::StringTable::Instance()->AddString("User", false);

		rakPeer->SetNetworkIDManager(&networkIdManager);
		networkIdManager.SetIsNetworkIDAuthority(false);
		SocketDescriptor socketDescriptor(atoi(ClientPort),0);
		rakPeer->Startup(1,0,&socketDescriptor, 1);
		rakPeer->AttachPlugin(&replicaManager);
		replicaManager.SetConnectionFactory(&connectionFactory);

		bool b = rakPeer->Connect(IP, atoi(ServerPort), Pass, (int) strlen(Pass));	
		
		//pfl.LogHeader();

		if (b)
		{
			//textQueueList->Add("Connecting to server...");
			OgreQueueText::instance()->Addf("Connecting to %s",IP);
			return true;
		}
		else
		{
			//textQueueList->Add("Failed connection!");
			return false;
		}
	}
	
	bool isConnected()
	{
		return rakPeer->IsActive();
	}
	
	void UpdateMyPlayer(Ogre::Vector3 p, Ogre::Vector3 vel, Ogre::Quaternion or)
	{
		if(Soldier::mySoldier) {
			Soldier::mySoldier->position = p;
			Soldier::mySoldier->velocity = vel;
			Soldier::mySoldier->orientation = or;
		}
	}

	/*
	Entity *ent;
	sceneNode = sceneMgr->getRootSceneNode()->createChildSceneNode();
    ent = sceneMgr->createEntity("enemy", "ninja.mesh");
    sceneNode->attachObject(ent);
	sceneNode->scale(Vector3(0.02,0.02,0.02));
	sceneNode->yaw(Ogre::Radian(Ogre::Degree(180)));
	sceneNode->setPosition(700, 700, 700);
	*/

	bool isWalking(Vector3 Position)
	{

		if(OldPos!=Position) {
			OldPos = Position;
			return true;
		}
		return false;
	}

	void UpdatePlayers(Real time) //RakNetTime
	{
		for (unsigned i=0; i < Soldier::soldiers.Size(); i++) {
			//OgreQueueText::instance()->Addf("%i. ptr=%p name=%s isCloaked=%i owner=%p\n", i+1, Soldier::soldiers[i], Soldier::soldiers[i]->name, Soldier::soldiers[i]->isCloaked, Soldier::soldiers[i]->owner);
			if(Soldier::soldiers[i]!=Soldier::mySoldier) {

				Soldier::soldiers[i]->UpdatePlayers(time);
				//OgreQueueText::instance()->Addf("%f.", Soldier::soldiers[i]->visiblePosition.x);
				//Soldier::soldiers[i]->visiblePosition.y = HeightFunction::getTerrainHeight(Soldier::soldiers[i]->visiblePosition.x, Soldier::soldiers[i]->visiblePosition.z);
				Soldier::soldiers[i]->sceneNode->setPosition(Soldier::soldiers[i]->visiblePosition);

				/*
				Vector3 src = Soldier::soldiers[i]->sceneNode->getOrientation() * Vector3::UNIT_X;  
				Vector3 dest = Soldier::soldiers[i]->visibleOrientation * Vector3::UNIT_X;
				src.y = 0;
				src.normalise();
				dest.y = 0;
				dest.normalise();
				Quaternion quat = src.getRotationTo(dest);
				Soldier::soldiers[i]->sceneNode->rotate(quat);
				*/

				//Soldier::soldiers[i]->sceneNode->setOrientation(quat);
				//mNode->rotate(quat);
				Soldier::soldiers[i]->sceneNode->setOrientation(Soldier::soldiers[i]->visibleOrientation);
				//Ogre::Radian r;
				//r = 0;
				//Soldier::soldiers[i]->sceneNode->pitch(r);

				//Soldier::soldiers[i]->sceneNode->yaw(Soldier::soldiers[i]->visibleOrientation.getYaw(false));
				//Soldier::soldiers[i]->sceneNode->setVisible(true);
				//if(isWalking(Soldier::soldiers[i]->visiblePosition)) {
					//Soldier::soldiers[i]->mAnimationState = ent->getAnimationState("Walk");
				//}
				//else
				//{
				//	Soldier::soldiers[i]->mAnimationState = ent->getAnimationState("Idle2");
				//}
				//OgreQueueText::instance()->Addf("Recieved State: %d", Soldier::soldiers[i]->State);
				
				//if(Soldier::soldiers[i]->mAnimationState_Current->hasEnded()) {
				//	Soldier::soldiers[i]->mAnimationState_Current->setLoop(true);
				//	Soldier::soldiers[i]->mAnimationState_Current->setEnabled(true);
				//}
				if(Soldier::soldiers[i]->Shooted == true) {
					Soldier::soldiers[i]->Shooted = false;
					//pm->Shoot(cameraNode->getPosition(),cameraYawNode->getOrientation()*cameraPitchNode->getOrientation()*mCamera->getDirection() ,2,14,cameraYawNode->getOrientation()*cameraPitchNode->getOrientation());
					Vector3 dir(0,0,0);
					dir.x = 0;
					dir.y = 0;
					dir.z = -1;
					Soldier::soldiers[i]->visiblePosition.y += 3; //+3 temporal solution to move arrow to camera view position
					pm->Shoot(Soldier::soldiers[i]->visiblePosition,Soldier::soldiers[i]->visibleOrientation * -Vector3::UNIT_Z,0.4,5,Soldier::soldiers[i]->visibleOrientation);
				}
				Soldier::soldiers[i]->mAnimationState_Current->addTime(time * Soldier::soldiers[i]->mAnimationSpeed);
				
				
				//OgreQueueText::instance()->Addf("%d.", Soldier::soldiers[i]->State);
				//scenenode->setPosition(Soldier::soldiers[i]->visiblePosition);
				//scenenode->setOrientation(Soldier::soldiers[i]->orientation);
				//debug1->showTextNormal("1: " + StringConverter::toString(Soldier::soldiers[i]->mAnimationState_Current->getLength()),300,330);
				//debug2->showTextNormal("or->x: " + StringConverter::toString(Soldier::soldiers[i]->mAnimationState_Current->),300,350);
				//debug3->showTextNormal("or->y: " + StringConverter::toString(Soldier::soldiers[i]->orientation.y),300,370);
				//debug4->showTextNormal("or->z: " + StringConverter::toString(Soldier::soldiers[i]->orientation.z),300,390);
			}
			else
			{
				//Soldier::soldiers[i]->sceneNode->setVisible(true);
				//Soldier::soldiers[i]->mAnimationState_Current->addTime(time);

				/*
				Vector3 src = Soldier::mySoldier->sceneNode->getOrientation() * Vector3::UNIT_X;  
				Vector3 dest = Soldier::mySoldier->visibleOrientation * Vector3::UNIT_X;
				src.y = 0;
				src.normalise();
				dest.y = 0;
				dest.normalise();
				Quaternion quat = src.getRotationTo(dest);
				Soldier::mySoldier->sceneNode->rotate(quat);
				*/

				//if(Soldier::mySoldier->mAnimationState_Current->hasEnded()) {
				//	Soldier::mySoldier->mAnimationState_Current->setLoop(true);
				//	Soldier::mySoldier->mAnimationState_Current->setEnabled(true);
				//}
				Soldier::mySoldier->mAnimationState_Current->addTime(time);

			}
		}
	}

	void ReceiveData()
	{
		for (packet = rakPeer->Receive(); packet; rakPeer->DeallocatePacket(packet), packet = rakPeer->Receive())
		{
			switch (packet->data[0])
			{
			case ID_CONNECTION_ATTEMPT_FAILED:
				OgreQueueText::instance()->Add("ID_CONNECTION_ATTEMPT_FAILED");
				break;
			case ID_NO_FREE_INCOMING_CONNECTIONS:
				OgreQueueText::instance()->Add("ID_NO_FREE_INCOMING_CONNECTIONS");
				break;
			case ID_CONNECTION_REQUEST_ACCEPTED:

				OgreQueueText::instance()->Add("ID_CONNECTION_REQUEST_ACCEPTED");
				Soldier::mySoldier = new Soldier();
				Soldier::mySoldier->SetReplicaManager(&replicaManager);
				Soldier::mySoldier->AddAutoSerializeTimer(DEFAULT_PLAYER_DELAY);
				Soldier::mySoldier->sceneNode->setVisible(true); //hide my character
				Soldier::mySoldier->BroadcastConstruction();
				
				break;
			case ID_NEW_INCOMING_CONNECTION:
				break;
			case ID_DISCONNECTION_NOTIFICATION:
			case ID_CONNECTION_LOST:
				break;
			}
		}
		RakSleep(0);
		return;
	}
private:

};

#endif